// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: wsfuyibing <682805@qq.com>
// Date: 2024-08-20

package gen_annotation

import (
	"fmt"
	"gitee.com/go-libs/console"
	"html/template"
	"regexp"
	"sort"
	"time"
)

type (
	// ResultHandler
	// is a component for handler annotation result.
	ResultHandler struct {
		Handlers         []*ResultHandlerHandler
		Package          string
		PackageList      []*ResultHandlerAlias
		Script, Datetime template.HTML

		aliasList   []string
		aliasMapper map[string]string
		aliasOffset int
	}

	// ResultHandlerAlias
	// is a component for package imports.
	ResultHandlerAlias struct {
		Alias string // a0
		Pkg   string // sketch/app/handlers
	}

	// ResultHandlerHandler
	// is a component for handler executors.
	ResultHandlerHandler struct {
		Line int    // 24
		File string // app/handlers/example_handler.go
		Func string // ExampleHandler
		Pkg  string // a0

		Method      string
		Middlewares []string
		Path        string
	}
)

// NewResultHandler
// creates a handler result component.
func NewResultHandler(command *console.Command, pkg string) *ResultHandler {
	return (&ResultHandler{
		Handlers:    make([]*ResultHandlerHandler, 0),
		Package:     pkg,
		PackageList: make([]*ResultHandlerAlias, 0),
	}).init(command)
}

// AddEntity
// add a handler entity.
func (o *ResultHandler) AddEntity(entity *EntityHandler) {
	o.Handlers = append(o.Handlers, &ResultHandlerHandler{
		Line: entity.Line,
		File: entity.File,
		Func: entity.Func,
		Pkg:  o.AddPackage(entity.Import, true),

		Method:      entity.Method,
		Middlewares: entity.Middlewares,
		Path:        entity.Uri,
	})
}

// AddPackage
// add a package import.
func (o *ResultHandler) AddPackage(pkg string, rename bool) (alias string) {
	pkg = regexp.MustCompile(`/+`).ReplaceAllString(pkg, `/`)

	// Reuse
	// previous alias name.
	if str, ok := o.aliasMapper[pkg]; ok {
		alias = str
		return
	}

	// Alias name generate.
	if rename {
		alias = fmt.Sprintf(`a%d`, o.aliasOffset)
		o.aliasOffset++
	}

	// Update alias mapping and list.
	o.aliasList = append(o.aliasList, pkg)
	o.aliasMapper[pkg] = alias

	// Update package info.
	return
}

// Ready
// is a hook when result ready.
func (o *ResultHandler) Ready() *ResultHandler {
	o.initPackages()
	return o
}

// +---------------------------------------------------------------------------+
// | Access methods                                                            |
// +---------------------------------------------------------------------------+

func (o *ResultHandler) init(command *console.Command) *ResultHandler {
	// Init
	// internal fields.
	o.aliasList = make([]string, 0)
	o.aliasMapper = make(map[string]string)

	// Init
	// basic fields.
	o.Datetime = template.HTML(time.Now().Format(time.RFC3339))
	o.Script = template.HTML(command.ToScript())

	// Add
	// builtin package.
	o.AddPackage("gitee.com/go-wares/framework-iris/framework", false)
	return o
}

func (o *ResultHandler) initPackages() {
	// Sort
	// package with alpha number.
	sort.Strings(o.aliasList)

	// Iterate
	// added packages then build package list.
	for _, pkg := range o.aliasList {
		// Build
		// alias component.
		item := &ResultHandlerAlias{Pkg: pkg}

		// Build
		// alias name.
		if alias, ok := o.aliasMapper[pkg]; ok {
			item.Alias = alias
		}

		// Add
		// to list.
		o.PackageList = append(o.PackageList, item)
	}
}
